(ns #^{:doc "The main driving core of the Jtacck server.
            Starts off the web server and Android server
            from given command-line arguments."}
  clj.jtacck.core
  (:use clojure.contrib.command-line
	clj.jtacck.logging)
  (:require [clojure.string :as string]
	    [clj.jtacck.web.core :as web]
	    [clj.jtacck.db.core :as db]
	    [clj.jtacck.cache :as cache])
  (:import jvm.jtacck.AndroidServer)
  (:gen-class))

(defn parse-config
  "Given a string consisting on formatted lines such as
        option=value
  returns a map from options to values. Whitespace will be
  trimmed around each option and value."
  [str]
  (when (and (string? str) (not (empty? str)))
   (into {}
	 (map (fn [[key value]] [(keyword key) value])
	      (map (fn [s] (map string/trim (string/split s #"=" 2)))
		   (string/split-lines str))))))

(defn -main [& args]
  (try
    (with-command-line args
      "Arguments/Usage:"
      [[config c "Location of configuration file." "config.txt"]
       [web-port w "Port for web server to listen on." "8080"]
       [android-route-port l "Port for Android server to listen on." "4000"]
       [android-request-port p "Port for Android server to push data on." "9001"]
       [no-web? "Don't start the web server."]
       [no-android? "Don't start the android server."]]
      (bind-stdouterr-to-logger) ; Begin piping std to log.
      (let [options (parse-config (slurp config))]
	(when-not
	    (db/start-db-connection (:db-username options)
				    (:db-password options)
				    (:db-address options))
	  (throw (RuntimeException. "Database connection could not be made.")))
	(when-not no-web?
	  (web/start-server (Integer/parseInt web-port)))
	(when-not no-android?
	  (doto (AndroidServer. (Integer/parseInt android-route-port)
				(Integer/parseInt android-request-port)) .start))
	(cache/start-cache-compactor)))
    (catch Exception e
      (println "ERROR:" (.getMessage e)))))